home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
smaltalk
/
st80_r41.lha
/
st80_r41
/
RDoItR41
/
Voss-rdoitR41.st
< prev
Wrap
Text File
|
1993-07-23
|
7KB
|
239 lines
'From Objectworks\Smalltalk(R), Release 4.1 of 15 April 1992 on 22 August 1992 at 11:53:11 am'!
Model subclass: #RDoItServer
instanceVariableNames: 'socket myPortNumber '
classVariableNames: 'BadHosts OkHosts '
poolDictionaries: ''
category: 'Voss-RDoIt'!
RDoItServer comment:
'First how to use:
[RDoItServer initialize.] To reset the authorized/unauthorized host sets.
[RDoItServer start.] or
[RDoItServer startAt: 8004.] To start a server on port (default 8004).
[RDoItServer killAll.] To kill all servers.
----------------------------------------------------------
This is a quick hack to allow an external C program to execute a Smalltalk doIt.
I built this so I could put the Launcher options on my X11 root menu.
I also wanted a tiny project to help me get back up to speed after
not writing any Smalltalk code for a long time.
The basic idea is that we start up a Smalltalk process which creates a socket,
and sits there listening for connections. When a connection comes in, it forks
a subprocess to do the actual work. This subprocess reads from the socket
until it sees a CR, and then evaluates what it has read (simillar to DoIt in a workspace).
The subprocess then closes its connection and dies, while the main process
continues to wait for connections.
The server also catches the #returnFromSnapshot update: message, and restarts itself.
(That is why it is a subclass of Model instead of Object.)
The external C program "rdoit hostname portnumber message" is similar to "rsh" in operation.
CAUTION: The doits are NOT logged in the change log.
DANGER: Security is done on a host by host basis. When a connection
comes in from a previously unrecognized host, a dialog box
pops up asking the user to authorize the host.
Select yes, and all future requests from that host will suceed.
Select no, and all future attempts will be denied.
(This is done with the Sets BadHosts and OkHosts.)
This means that while the server is running, ANY user on any
authorized host could have your st80 process do anything.
Including run any program on the system SO BE CAREFUL!!
FUTURE WORK:
Fix security problems.
(There are only two people with accounts on my system,
so I personally am not going to "fix" this problem anytime soon.)
VERSION LOG:
June 14th, 1991 -- The Original Version, written for R4.0
August 22nd, 1992 -- This Version created for R4.1
Made RDoItServer a subclass of Model, and fixed the "release" method.
Changed from being a dependent of Smalltalk to being a dependent of ObjectMemory.
Bill Voss <voss@cs.uiuc.edu> August 22nd, 1992
'!
!RDoItServer methodsFor: 'initialize-release'!
release
(socket isKindOf: UnixSocketAccessor)
ifTrue: [socket close].
socket removeDependent: self.
ObjectMemory removeDependent: self.
super release.
socket := nil! !
!RDoItServer methodsFor: 'restart-update'!
restart
"Called when snapshot is started, and at instance creation."
[self loopForever]
forkAt: self serverPriority.
Transcript cr; show: 'RDoItServer restarted with --'.
self showHosts: Transcript.
^self!
startServer
"This is only run by SERVER instances at startup."
ObjectMemory addDependent: self.
self restart.
^self!
startServerAt: aPortNumber
"This is only run by SERVER instances at startup."
myPortNumber := aPortNumber.
^self startServer!
update: aSymbol
"Dependents of SystemDictionary Smalltalk are sent update:
#returnFromSnapshot when a snapshot is started."
aSymbol == #returnFromSnapshot ifTrue: [self restart].
super update: aSymbol.
^self! !
!RDoItServer methodsFor: 'host management'!
confirmNewHost: who
"A previously unauthorized host is trying to connect."
"Ask the user if we can authorize this new host."
| answer |
answer := DialogView confirm: 'RDOIT ok from host ' , who hostName printString , '?' initialAnswer: true.
answer
ifTrue: [OkHosts add: who hostName]
ifFalse: [BadHosts add: who hostName].
^answer!
showHosts: aTextCollector
"Output the current hosts, normally to Transcript."
aTextCollector crtab; show: 'Authorized Hosts '.
aTextCollector print: OkHosts.
aTextCollector crtab; show: 'Unauthorized Hosts '.
aTextCollector print: BadHosts.
aTextCollector cr; show: ''! !
!RDoItServer methodsFor: 'handle client'!
handleClient: aSocket
"This method is forked off when a new connection arrives."
| who deniedBlock |
who := aSocket getPeer.
deniedBlock := [Transcript cr; show: 'Denied rdoit attempt from: ' , who printString].
(BadHosts includes: who hostName)
ifTrue: deniedBlock
ifFalse: [(OkHosts includes: who hostName)
ifTrue: [self handleOkClient: aSocket]
ifFalse: [(self confirmNewHost: who)
ifTrue: [self handleOkClient: aSocket]
ifFalse: deniedBlock]].
aSocket close.
^nil!
handleOkClient: aSocket
"We read through cr, and then doit."
"Note: evaluate:logged: requires textOrString if logged = true."
| exConn nStrm aCollection |
exConn := ExternalConnection ioAccessor: aSocket.
nStrm := exConn readAppendStream.
aCollection := nStrm through: Character cr.
^Compiler
evaluate: aCollection readStream
for: self
logged: false!
loopForever
"Called when snapshot is started, and at instance creation."
"I create and listen to my socket."
"Note: Someone else has already forked me, so I can block."
"SEE ALSO: UnixSocketAccessor class howToImplementAServer."
| newskt thisSocket |
thisSocket := UnixSocketAccessor newTCPserverAtPort: self portNumber.
thisSocket notNil
ifTrue: [socket := thisSocket]
ifFalse: [^nil].
thisSocket listenFor: 5.
newskt := true.
[socket == thisSocket and: [newskt notNil]]
whileTrue:
[newskt := socket accept.
newskt notNil ifTrue: [[self handleClient: newskt]
forkAt: self handlePriority]].
thisSocket notNil ifTrue: [thisSocket close].
self release.
^nil! !
!RDoItServer methodsFor: 'constants'!
handlePriority
"The priority a handler process should run at."
^Processor lowIOPriority!
serverPriority
"The priority the server process should run at."
^Processor lowIOPriority! !
!RDoItServer methodsFor: 'private'!
portNumber
"Return my port number."
"Default st80 R4 == 8004 (totally arbitrary)."
myPortNumber isNil
ifTrue: [^8004]
ifFalse: [^myPortNumber]! !
"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "!
RDoItServer class
instanceVariableNames: ''!
!RDoItServer class methodsFor: 'class initialization'!
initialize
"Initialize class variables."
"RDoItServer initialize."
BadHosts := Set new.
OkHosts := Set new! !
!RDoItServer class methodsFor: 'instance creation'!
start
"Start an rdoit server on the default port."
"RDoItServer start."
^self new startServer!
startAt: aPortNumber
"Start an rdoit server on a specified port."
"RDoItServer startAt: 8004."
^self new startServerAt: aPortNumber! !
!RDoItServer class methodsFor: 'server destruction'!
killAll
"Destroy all instances of the server."
"RDoItServer killAll."
RDoItServer allInstances do: [:a | a release].
^nil! !
RDoItServer initialize!